﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Platform.Storage.Entity;
using Platform.ObjectModel;
using System.Diagnostics;

namespace Platform.Storage.Impl
{
	/// <summary>
	/// Realiza o controle e manutenção dos contextos criados durante a tradução de uma expressão LINQ
	/// </summary>
	internal sealed class ContextManager
	{
		private Stack<Context> contexts = new Stack<Context>();
		private Stack<string> methodsFromContext = new Stack<string>();	// Métodos que pertencem ao próximo contexto

		/// <summary>
		/// 
		/// </summary>
		/// <param name="expander"></param>
		public ContextManager( )
		{
			//this.Expander = expander;
		}

		/// <summary>
		/// Obtém ou define o objeto utilizado para resolver os nomes das entidades do sistema
		/// </summary>
		//public IQueryResolver Expander
		//{ get; private set; }

		/// <summary>
		/// Obtém o contexto atual da tradução
		/// </summary>
		public Context Current
		{ get { return this.contexts.Peek(); } }

		/// <summary>
		/// Obtém todos os contextos criados durante a tradução da expressão
		/// </summary>
		internal Stack<Context> AllContexts
		{ get { return this.contexts; } }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="parent"></param>
		/// <returns></returns>
		public Context CreateScope( Context parent )
		{
			return this.CreateScope( parent.Entity, parent.QueryBase, parent.QualifiedName, parent.EntityType, parent.Resolver );
		}

		/// <summary>
		/// Cria um novo contexto de tradução de uma expressão
		/// </summary>
		/// <param name="entity"></param>
		/// <param name="query"></param>
		/// <returns></returns>
		public Context CreateScope( Expression entity, Expression query, DataObjectName name, Type entityType, IQueryResolver resolver )
		{
			var context = new Context( this ) { Entity = entity, QueryBase = query, Resolver = resolver };
			context.Methods = this.methodsFromContext;
			context.QualifiedName = name;
			context.EntityType = entityType;
			this.methodsFromContext = new Stack<string>();
			this.contexts.Push( context );
			return context;
		}

		public void ReleaseContext( Context ctx )
		{
			Debug.Assert( this.AllContexts.Count > 0 );

			if ( !this.AllContexts.Peek().Equals( ctx ) )
			{
				throw new InvalidOperationException();
			}
			this.AllContexts.Pop();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="method"></param>
		public void PushMethod( string method )
		{
			this.methodsFromContext.Push( method );
		}

		//public int GetCurrentTokenID()
		//{
		//    return this.contexts.Count + 1;
		//}

		///// <summary>
		///// Realiza a criação da query, baseado no contexto
		///// </summary>
		///// <returns></returns>
		//public Expression QueryFromContext()
		//{
		//	var context = this.contexts.Pop();
		//	IQueryable<string> tokenFilter = context.CreateFilterCriteria();

		//	// Verifica se necessita ignora ou limitar a quantidade de
		//	// registros que serão retornados
		//	if ( context.SkipCount != null
		//		|| context.TakeCount != null )
		//	{
		//		if ( context.SkipCount != null )
		//			tokenFilter = tokenFilter.Skip( ( int )context.SkipCount.CompileAndGetValue() );

		//		if ( context.TakeCount != null )
		//			tokenFilter = tokenFilter.Take( ( int )context.TakeCount.CompileAndGetValue() );
		//	}

		//	// Realiza as agregações
		//	if ( context.IsAggregate )
		//	{
		//		return TranslatorHelper.MakeQueryableCall( typeof( string ), context.AggregateMethod, Expression.Constant( tokenFilter ) );
		//	}
		//	else
		//	{
		//		Expression<Func<FieldValue, bool>> fieldFilters = entityField => tokenFilter.Contains( entityField.ReversedTokenId );
		//		return TranslatorHelper.MakeQueryableCall( "Where", context.QueryBase, fieldFilters );
		//	}
		//}
	}
}
